package jupiter.messaging;

import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.regex.Pattern;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import jupiter.util.DBConnection;
import jupiter.util.MemCache;
import jupiter.util.Timey;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import javax.naming.InitialContext;
import javax.sql.DataSource;

public class Inbox {
	
	public String name;
	public String website;
	public String id;
	
	public String session_id;
	public String location;
	public String call_id;
	public boolean is_banned;
	public String page;
	public boolean read_only = false;
	public boolean is_registered = true;
	private Hashtable<String, Hashtable<String, Collection<Message>>> objects;
	Logger logger = LoggerFactory.getLogger(Inbox.class);
	
	public Inbox( Message m, HttpSession s) {
		super();
		page = m.page;
		call_id = m.from;
		id = m.user_id;
		name = m.name;
		website = m.website;
		is_banned = this.isBanned(m);
		objects = new Hashtable<String, Hashtable<String, Collection<Message>>>();
		boolean domain_found = MemCache.get_domain(m.domainName());
		if(domain_found == false) {
			is_registered = false;
		}
	}
	/**
	 * Constructor is only used for read_only connections
	 * @param m
	 * @param s
	 * @param read
	 */
	public Inbox( Message m, HttpSession s, boolean read) {
		super();
		read_only = true;
		page = m.page;
		is_banned = false;
		objects = new Hashtable<String, Hashtable<String, Collection<Message>>>();
		boolean domain_found = MemCache.get_domain(m.domainName());
		if(domain_found == false) {
			is_registered = false;
		}
	}
	public String domain(){
		return ApplicationAddressBook.getDomainName(page);
	}

	/*
	 * Checks for active_user in the database, if not found creates it
	 * @return true if the user is banned, false if they are allowed to create messages
	 */
	private boolean isBanned(Message m){
		Connection conn = null;
	    Statement stmt = null;
	    ResultSet rs = null;
	    String name = null;
		try {
			name = m.parsed.getString("name");
		} catch (JSONException e1) {
			logger.error("JSONException", e1);
		}
		// am i banned?
		// perform asynchronous insert, don't wait for result
		Timey t = new Timey();
		try{		
			conn = DBConnection.ds.getConnection();
			stmt = conn.createStatement();
			rs = stmt.executeQuery("SELECT a.can_create_messages, a.call_id FROM active_users a WHERE a.id='"+m.user_id+"';");
			t.end("BannedDB");
			boolean row = rs.next();
			if(!row) { // not found, create it
				String create_qry = "INSERT INTO active_users "+
					"(id, name, created_at, updated_at, can_create_messages, call_id) "+
					"VALUE('"+id+"', '"+name+"', NOW(),NOW(),1, '"+call_id+"');";
				try{
					stmt.executeUpdate(create_qry);
				} catch(SQLException e) {
					try{
				        rs.close();
				        stmt.close();
				        conn.close();
			        } catch(SQLException close_e){
						logger.error("SQLException: ERROR in closing connections", close_e);
			        }
					logger.error("SQLException: "+create_qry+" SelectQuery: "+"SELECT a.can_create_messages, a.call_id FROM active_users a WHERE a.id='"+m.user_id+"';", e);
				}
				t.end("CreateDB");
		        rs.close();
		        stmt.close();
		        conn.close();
				return false;
			}
			// there should only be one match
			else {
				String saved_call_id = rs.getString("a.call_id");
				logger.info("saved_call_id:"+saved_call_id);
				logger.info("call_id:"+call_id);
				if(saved_call_id == null || !saved_call_id.equals(call_id)){
					//UPDATE jabbify_production.active_users SET call_id="aaaa" WHERE id=1;
					String update_qry = "UPDATE active_users SET call_id='"+call_id+"' WHERE id='"+m.user_id+"';";
					stmt.executeUpdate(update_qry);
				}
				boolean result = rs.getBoolean("a.can_create_messages");
		        rs.close();
		        stmt.close();
		        conn.close();
	            return !result;
			}
		}catch(SQLException e){
			try{
		        rs.close();
		        stmt.close();
		        conn.close();
	        } catch(SQLException close_e){
				logger.error("SQLException: ERROR in closing connections", close_e);
	        }
			logger.error("SQLException", e);
		}
		return true;
	}
	public void addObject(Message o){
		String name =  o.type;
		String status = o.action;
		//synchronized(this) {
			Hashtable hash = (Hashtable) objects.get(name);
		    
			if(hash == null) {
		        hash = new Hashtable<String, Collection<Message>>();
		        objects.put(name, hash);
		    }
			Collection<Message> kinds = (Collection<Message>) hash.get(status);
			if(kinds == null){
				kinds = new ArrayList<Message>();
				hash.put(status, kinds);
			}
			kinds.add(o);
		//}
	}
	public void ban(boolean ban){
		is_banned = ban;
	}

	/**
	 * @return
	 */
	public String getMessages()  throws JSONException  {
		JSONObject classes = new JSONObject();
		String info = "";
		synchronized(this) {  //might not be needed b/c there is only one session that should ever grab this
			if(objects.isEmpty()) return "null";

			for(Enumeration<String> e = objects.keys(); e.hasMoreElements() ;){
				
				String name = e.nextElement();
				Hashtable<String, Collection<Message>> hash = (Hashtable<String, Collection<Message>>) objects.get(name);
				info += " "+name;
				
				JSONObject events = new JSONObject();
				for(Enumeration<String> hash_e = hash.keys(); hash_e.hasMoreElements() ;){
					String status = hash_e.nextElement();
					
					Collection<Message> kinds = (Collection<Message>) hash.get(status);
					
					info+= "{"+status+":"+kinds.size()+"}";
					JSONArray kind_array = new JSONArray();
					
					for(Message o : kinds){
						kind_array.put(o.parsed);
					}
					
					events.put(status, kind_array);
	
					kinds.clear();
				}
				info+= " ";
				classes.put(name, events);
	
				hash.clear();
			}
			objects.clear();
		}
		logger.info("     sending  :"+info);
		return classes.toString();
	}
	
}
